#include <string>
#include <boost/lexical_cast.hpp>

#include "Reply.h"
#include "Header.h"


using namespace std;
using namespace boost::asio;
using namespace tbb;


namespace StatusStrings
{
	const string ok = "HTTP/1.0 200 OK\r\n";
	const string created = "HTTP/1.0 201 Created\r\n";
	const string accepted = "HTTP/1.0 202 Accepted\r\n";
	const string noContent = "HTTP/1.0 204 No Content\r\n";
	const string multipleChoices = "HTTP/1.0 300 Multiple Choices\r\n";
	const string movedPermanently = "HTTP/1.0 301 Moved Permanently\r\n";
	const string movedTemporarily = "HTTP/1.0 302 Moved Temporarily\r\n";
	const string notModified = "HTTP/1.0 304 Not Modified\r\n";
	const string badRequest = "HTTP/1.0 400 Bad Request\r\n";
	const string unauthorized = "HTTP/1.0 401 Unauthorized\r\n";
	const string forbidden = "HTTP/1.0 403 Forbidden\r\n";
	const string notFound = "HTTP/1.0 404 Not Found\r\n";
	const string internalServerError = "HTTP/1.0 500 Internal Server Error\r\n";
	const string notImplemented = "HTTP/1.0 501 Not Implemented\r\n";
	const string badGateway = "HTTP/1.0 502 Bad Gateway\r\n";
	const string serviceUnavailable = "HTTP/1.0 503 Service Unavailable\r\n";

	const_buffer ToBuffer(Reply::StatusType status)
	{
		switch (status)
		{
		case Reply::Ok:
			return buffer(ok);
		case Reply::Created:
			return buffer(created);
		case Reply::Accepted:
			return buffer(accepted);
		case Reply::NoContent:
			return buffer(noContent);
		case Reply::MultipleChoices:
			return buffer(multipleChoices);
		case Reply::MovedPermanently:
			return buffer(movedPermanently);
		case Reply::MovedTemporarily:
			return buffer(movedTemporarily);
		case Reply::NotModified:
			return buffer(notModified);
		case Reply::BadRequest:
			return buffer(badRequest);
		case Reply::Unauthorized:
			return buffer(unauthorized);
		case Reply::Forbidden:
			return buffer(forbidden);
		case Reply::NotFound:
			return buffer(notFound);
		case Reply::InternalServerError:
			return buffer(internalServerError);
		case Reply::NotImplemented:
			return buffer(notImplemented);
		case Reply::BadGateway:
			return buffer(badGateway);
		case Reply::ServiceUnavailable:
			return buffer(serviceUnavailable);
		default:
			return buffer(internalServerError);
		}
	}
} // namespace StatusStrings

namespace MiscStrings
{
	const char nameValueSeparator[] = { ':', ' ' };
	const char crlf[] = { '\r', '\n' };
} // namespace MiscStrings

vector<const_buffer, scalable_allocator<const_buffer> > Reply::ToBuffers() const
{
	vector<const_buffer, scalable_allocator<const_buffer> > buffers;
	buffers.push_back(StatusStrings::ToBuffer(status));

	for (size_t i = 0; i < headers.size(); ++i)
	{
		const Header &h = headers[i];
		buffers.push_back(buffer(h.name));
		buffers.push_back(buffer(MiscStrings::nameValueSeparator));
		buffers.push_back(buffer(h.value));
		buffers.push_back(buffer(MiscStrings::crlf));
	}

	buffers.push_back(buffer(MiscStrings::crlf));
	buffers.push_back(buffer(content));

	return buffers;
}

namespace StockReplies
{
	const char ok[] = "";

	const char created[] =
		"<html>"
		"<head><title>Created</title></head>"
		"<body><h1>201 Created</h1></body>"
		"</html>";

	const char accepted[] =
		"<html>"
		"<head><title>Accepted</title></head>"
		"<body><h1>202 Accepted</h1></body>"
		"</html>";

	const char noContent[] =
		"<html>"
		"<head><title>No Content</title></head>"
		"<body><h1>204 Content</h1></body>"
		"</html>";

	const char multipleChoices[] =
		"<html>"
		"<head><title>Multiple Choices</title></head>"
		"<body><h1>300 Multiple Choices</h1></body>"
		"</html>";

	const char movedPermanently[] =
		"<html>"
		"<head><title>Moved Permanently</title></head>"
		"<body><h1>301 Moved Permanently</h1></body>"
		"</html>";

	const char movedTemporarily[] =
		"<html>"
		"<head><title>Moved Temporarily</title></head>"
		"<body><h1>302 Moved Temporarily</h1></body>"
		"</html>";

	const char notModified[] =
		"<html>"
		"<head><title>Not Modified</title></head>"
		"<body><h1>304 Not Modified</h1></body>"
		"</html>";

	const char badRequest[] =
		"<html>"
		"<head><title>Bad Request</title></head>"
		"<body><h1>400 Bad Request</h1></body>"
		"</html>";

	const char unauthorized[] =
		"<html>"
		"<head><title>Unauthorized</title></head>"
		"<body><h1>401 Unauthorized</h1></body>"
		"</html>";

	const char forbidden[] =
		"<html>"
		"<head><title>Forbidden</title></head>"
		"<body><h1>403 Forbidden</h1></body>"
		"</html>";

	const char notFound[] =
		"<html>"
		"<head><title>Not Found</title></head>"
		"<body><h1>404 Not Found</h1></body>"
		"</html>";

	const char internalServerError[] =
		"<html>"
		"<head><title>Internal Server Error</title></head>"
		"<body><h1>500 Internal Server Error</h1></body>"
		"</html>";

	const char notImplemented[] =
		"<html>"
		"<head><title>Not Implemented</title></head>"
		"<body><h1>501 Not Implemented</h1></body>"
		"</html>";

	const char badGateway[] =
		"<html>"
		"<head><title>Bad Gateway</title></head>"
		"<body><h1>502 Bad Gateway</h1></body>"
		"</html>";

	const char serviceUnavailable[] =
		"<html>"
		"<head><title>Service Unavailable</title></head>"
		"<body><h1>503 Service Unavailable</h1></body>"
		"</html>";

	string ToString(Reply::StatusType status)
	{
		switch (status)
		{
		case Reply::Ok:
			return ok;
		case Reply::Created:
			return created;
		case Reply::Accepted:
			return accepted;
		case Reply::NoContent:
			return noContent;
		case Reply::MultipleChoices:
			return multipleChoices;
		case Reply::MovedPermanently:
			return movedPermanently;
		case Reply::MovedTemporarily:
			return movedTemporarily;
		case Reply::NotModified:
			return notModified;
		case Reply::BadRequest:
			return badRequest;
		case Reply::Unauthorized:
			return unauthorized;
		case Reply::Forbidden:
			return forbidden;
		case Reply::NotFound:
			return notFound;
		case Reply::InternalServerError:
			return internalServerError;
		case Reply::NotImplemented:
			return notImplemented;
		case Reply::BadGateway:
			return badGateway;
		case Reply::ServiceUnavailable:
			return serviceUnavailable;
		default:
			return internalServerError;
		}
	}
} // namespace StockReplies

Reply Reply::StockReply(Reply::StatusType status)
{
	Reply rep;
	rep.status = status;
	rep.content = StockReplies::ToString(status);
	rep.headers.resize(2);
	rep.headers[0].name = "Content-Length";
	rep.headers[0].value = boost::lexical_cast<string>(rep.content.size());
	rep.headers[1].name = "Content-Type";
	rep.headers[1].value = "text/html";
	return rep;
}